// OnionChart.cpp: implementation of the COnionChart class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>
#include "StructSnapshot.h"
#include "OnionChart.h"

#include "ftManager.h"
#include "ftNode.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

const UINT LEVEL_BODER = 1;
const FLOAT PI = 3.1415926f;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

COnionChart::COnionChart()
:m_nlevelboder(LEVEL_BODER)
,m_pftTree(0)
{

}

COnionChart::~COnionChart()
{

}
BEGIN_MESSAGE_MAP(COnionChart, CWnd)
	ON_WM_PAINT()
END_MESSAGE_MAP()

void COnionChart::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	// TODO: Add your message handler code here
	// Do not call __super::OnPaint() for painting messages

	////gdiplus
	Graphics g(dc.m_hDC);
//	g.SetSmoothingMode(SmoothingModeHighQuality);
	//
	GetClentsquareRect(&m_drawrect);
	//
	DrawLevels(g);

	//gdi
	//GetClentsquareRect(&m_drawrect);
	//DrawLevels(&dc);
}

//void COnionChart::DrawLevels(CDC* pDC)
//{
//	RECT rect;
//
//	LOGBRUSH logBrush;
//	logBrush.lbStyle=BS_NULL;
//	CBrush hollowBrush;
//	hollowBrush.CreateBrushIndirect(&logBrush);
//    CBrush* oldBrush = pDC->SelectObject(&hollowBrush);
//	GetLevelRect(rect, 0);
//	pDC->Ellipse(&rect);
//
//	for (UINT i=0; i<m_nlevel; i++)
//	{
//		GetLevelRect(rect, i);
//		pDC->Ellipse(&rect);
//	}
//	pDC->SelectObject(oldBrush);
//
//}

void COnionChart::DrawLevels(Graphics& g)
{
	//level 0, root
	Pen pen(Color(255,0,0,0), (FLOAT)m_nlevelboder);

	Rect rect;
	GetLevelRect(rect, 0);
	g.DrawEllipse(&pen, rect);

	//for (int i=1; i<m_nlevel; i++)
	//{
	//	chLevel* pLevel = m_arrLevel[i];
	//	int size = pLevel->arrItem.GetSize();
	//	FLOAT sweepangle =0;
	//	for (int j=0; j<size; j++)
	//	{

	//		FLOAT angle = (FLOAT)(pLevel->arrItem[j]->size)/(FLOAT)(pLevel->total)*360;
	//		DrawSector(g, i, sweepangle, angle);
	//		sweepangle += angle;
	//	}
	//}
	if (m_pftTree == 0)
	{
		return;
	}
	if ((m_pftTree->IsTraversing() == FALSE)&&(m_pftTree->m_pRootNode!=NULL))
	{
		ftNode* pNode = m_pftTree->m_pRootNode;
		UINT nLevle = 1;
		//while ()
		{
			UINT nSize = pNode->m_arrSubNode.GetSize();
			LARGE_INTEGER lnTotal = {pNode->m_dwNodeSizeLow, pNode->m_dwNodeSizeHigh};
			LARGE_INTEGER lnParent;
			if (pNode->m_pParent ==NULL)
			{
				lnParent.HighPart = lnTotal.HighPart;
				lnParent.LowPart = lnTotal.LowPart;
			}
			else
			{
				lnParent.LowPart = pNode->m_pParent->m_dwNodeSizeLow;
				lnParent.HighPart = pNode->m_pParent->m_dwNodeSizeHigh;
			}
			FLOAT angleper = ((FLOAT)lnTotal.QuadPart / (FLOAT)lnParent.QuadPart)*360.0f;
			FLOAT sweepangle =0;
			for (int i=0; i<nSize; i++)
			{
				ftNode* pCurNode = pNode->m_arrSubNode[i];
				LARGE_INTEGER lnCur = {pCurNode->m_dwNodeSizeLow, pCurNode->m_dwNodeSizeHigh};
				FLOAT angle = ((FLOAT)lnCur.QuadPart / (FLOAT)lnTotal.QuadPart)*angleper;
				DrawSector(g, nLevle, sweepangle, angle);
				sweepangle += angle;
			}
		}
		pNode = pNode->m_arrSubNode[0];
		UINT nSize = pNode->m_arrSubNode.GetSize();
		nLevle++;
		LARGE_INTEGER lnTotal = {pNode->m_dwNodeSizeLow, pNode->m_dwNodeSizeHigh};
		LARGE_INTEGER lnParent = {pNode->m_pParent->m_dwNodeSizeLow, pNode->m_pParent->m_dwNodeSizeHigh};
		FLOAT angleper = ((FLOAT)lnTotal.QuadPart / (FLOAT)lnParent.QuadPart)*360.0f;
		FLOAT sweepangle =0;
		for (int i=0; i<nSize; i++)
		{
			ftNode* pCurNode = pNode->m_arrSubNode[i];
			LARGE_INTEGER lnCur = {pCurNode->m_dwNodeSizeLow, pCurNode->m_dwNodeSizeHigh};
			FLOAT angle = ((FLOAT)lnCur.QuadPart / (FLOAT)lnTotal.QuadPart)*angleper;
			DrawSector(g, nLevle, sweepangle, angle);
			sweepangle += angle;
		}
	}
}

void COnionChart::DrawSector(Graphics& g, UINT nLevel, FLOAT startAngle, FLOAT sweepAngle)
{
	Pen pen(Color(255, 0, 0 ,0));
	Rect levelRect;
	POINT centerPoint = {m_drawrect.left+(m_drawrect.right-m_drawrect.left)/2, m_drawrect.top+(m_drawrect.bottom-m_drawrect.top)/2};

	GetLevelRect(levelRect, nLevel);
	g.DrawArc(&pen, levelRect, startAngle, sweepAngle);
	UINT nlen = levelRect.Width/2;
	POINTF outStart;
	FLOAT radian= startAngle*PI/180.0f;
	outStart.x = centerPoint.x + nlen* cos(radian);
	outStart.y = centerPoint.y + nlen* sin(radian);
	POINTF outEnd;
	radian= (startAngle+ sweepAngle)*PI/180.0f;
	outEnd.x = centerPoint.x + nlen* cos(radian);
	outEnd.y = centerPoint.y + nlen* sin(radian);

	GetLevelRect(levelRect, nLevel-1);
//	g.DrawArc(&pen, levelRect, startAngle, sweepAngle);
	nlen = levelRect.Width/2;
	POINTF inStart;
	radian= startAngle*PI/180.0f;
	inStart.x = centerPoint.x + nlen* cos(radian);
	inStart.y = centerPoint.y + nlen* sin(radian);
	POINTF inEnd;
	radian= (startAngle+ sweepAngle)*PI/180.0f;
	inEnd.x = centerPoint.x + nlen* cos(radian);
	inEnd.y = centerPoint.y + nlen* sin(radian);
	g.DrawLine(&pen, inStart.x, inStart.y, outStart.x, outStart.y);
	g.DrawLine(&pen, inEnd.x, inEnd.y, outEnd.x, outEnd.y);
}

void COnionChart::GetClentsquareRect(RECT* rect)
{
	GetClientRect(rect);
	int x = rect->right -rect->left;
	int y = rect->bottom -rect->top;
	if (x < y)
	{
		rect->top += abs(y-x)/2;
		rect->bottom = rect->top + x;
	}
	if (x > y)
	{
		rect->left += abs(y-x)/2-1;
		rect->right = rect->left + y;
	}
	rect->bottom--;
	rect->right--;
}

BOOL COnionChart::GetLevelRect(RECT& rect, UINT nLevel)
{
	nLevel++;
	if ((nLevel<=0) || (nLevel>m_nlevel+1))
	{
		return FALSE;
	}
	UINT nLevelLength(0);
	nLevelLength = (m_drawrect.right - m_drawrect.left)/2/m_nlevel;
	if (nLevelLength <= 0)
	{
		nLevelLength = 1;
	}
	
	POINT centerPoint = {m_drawrect.left+(m_drawrect.right-m_drawrect.left)/2, m_drawrect.top+(m_drawrect.bottom-m_drawrect.top)/2};

	rect.left = centerPoint.x - nLevelLength*nLevel;
	rect.top = centerPoint.y - nLevelLength*nLevel;
	rect.right = centerPoint.x + nLevelLength*nLevel;
	rect.bottom = centerPoint.y + nLevelLength*nLevel;

	return TRUE;
}

BOOL COnionChart::GetLevelRect(Rect& rect, UINT nLevel)
{
	nLevel++;
	if ((nLevel<=0) || (nLevel>m_nlevel))
	{
		return FALSE;
	}
	UINT nLevelLength(0);
	nLevelLength = (m_drawrect.right - m_drawrect.left)/2/m_nlevel;
	if (nLevelLength <= 0)
	{
		nLevelLength = 1;
	}
	
	POINT centerPoint = {m_drawrect.left+(m_drawrect.right-m_drawrect.left)/2, m_drawrect.top+(m_drawrect.bottom-m_drawrect.top)/2};

	rect.X = centerPoint.x-nLevelLength*nLevel;
	rect.Y = centerPoint.y-nLevelLength*nLevel;
	rect.Width = nLevelLength*nLevel*2;
	rect.Height = nLevelLength*nLevel*2;
	return TRUE;
}

BOOL COnionChart::GetLevelFillRect(Rect& rect, UINT nLevel)
{
	if (GetLevelRect(rect, nLevel))
	{
		rect.X += m_nlevelboder;
		rect.Y += m_nlevelboder;
		rect.Width -= m_nlevelboder*2;
		rect.Height -= m_nlevelboder*2;
		return TRUE;
	}
	return FALSE;
}

BOOL COnionChart::LoadTree(ftManager* ftTree)
{
	m_pftTree = ftTree;
	if (m_pftTree ==NULL)
	{
		return FALSE;
	}
	m_nlevel = m_pftTree->m_pRootNode->m_nSubLevel;
	return TRUE;
}
